package com.ruoyi.file.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.file.domain.FileChunkInfo;
import com.ruoyi.file.domain.TFileInfoVO;
import com.ruoyi.file.service.IFileChunkInfoService;
import com.ruoyi.file.service.IFileInfoService;
import com.ruoyi.framework.minio.MinioFile;
import com.ruoyi.framework.minio.MinioService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 上传下载文件
 *
 * @author 任伟伟
 * 文件上传接口
 * 该接口也支持大文件(GB级别以上)上传
 * 前端请使用BigFileUploader组件
 * 该请求建议根据参数hash到服务器上
 * minio 分片上传
 * https://blog.csdn.net/m0_67402970/article/details/126112680
 */
@RestController
@RequestMapping("/file/uploader")
public class FileMinioChunkController extends BaseController {
    private final Logger logger = LoggerFactory.getLogger(FileMinioChunkController.class);
    @Autowired
    private IFileChunkInfoService fileChunkInfoService;
    @Autowired
    private MinioService minioService;
    private static final String minio_key="minio_file";


    //实现秒传接口
    @GetMapping("/chunk")
    public AjaxResult checkChunk(FileChunkInfo chunk, HttpServletResponse response) {
        //文件已经上传并且合并过了
//        Boolean fileUploadAndMerges = redisCache.getCacheObject(minio_key+chunk.getIdentifier());
//        //先判断整个文件是否已经上传过了，如果是，则告诉前端跳过上传，实现秒传
//        if (fileUploadAndMerges!=null&&fileUploadAndMerges) {//如果完整文件存在
//            JSONObject data = new JSONObject();
//            data.put("skipUpload",true);
//            return AjaxResult.success("完整文件已存在，直接跳过上传，实现秒传",data);
//        }
        //文件还没合并,把上传的分片表给前端
        ArrayList<Integer> list = fileChunkInfoService.checkChunk(chunk);
        if(list!=null&&list.size()==chunk.getTotalChunks()){
            //之前未合并--之间跳过，然后合并
            JSONObject data = new JSONObject();
            data.put("skipUpload",true);
            data.put("state",2000);
            data.put("totalChunks",chunk.getTotalChunks());
            return AjaxResult.success("文件已经分片上传完毕，需要合并操作",data);
        }
        JSONObject data = new JSONObject();
        data.put("uploaded",list);//当前文件已经上传完成的chunk
        return AjaxResult.success("已经上传的文件列表",data);
    }

    /**
     * 上传文件块
     *
     * @param chunk
     * @return http://localhost:7777/dev-api/file/uploader/chunk?chunkNumber=1&chunkSize=2048000&currentChunkSize=2048000
     * &totalSize=6904810&identifier=19b01e74f140975ad6d95d77018949bc&filename=wgs84china.zip
     * &relativePath=wgs84china.zip&totalChunks=4
     */
    @PostMapping("/chunk")
    public AjaxResult uploadChunk(FileChunkInfo chunk) {
        try {
            MultipartFile file = chunk.getUpfile();
            logger.info("post  file originName: {}, chunkNumber: {}",file.getOriginalFilename(),chunk.getChunkNumber());
            //写入minio
            minioService.makeBucket(chunk.getIdentifier());
            String objectName = String.valueOf(chunk.getChunkNumber());
            minioService.putChunkObject(file.getInputStream(),chunk.getIdentifier(),objectName);
            if (fileChunkInfoService.saveChunk(chunk) < 0) {
                return AjaxResult.error("上传文件异常");
            }else {
                List<String> uploadedChunks = minioService.listObjectNames(chunk.getIdentifier());
                JSONObject data = new JSONObject();
                if(chunk.getTotalChunks().intValue()==uploadedChunks.size()){//当前文件块
                    data.put("state",2000);//上传完成
                    data.put("totalChunks",chunk.getTotalChunks());
                }else {
                    data.put("state",2001);//继续上传
                }
                logger.info("上传文件成功-----------");
                return AjaxResult.success("上传文件成功",data);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("上传文件异常");
        }
    }



    @PostMapping("/mergeFile")
    public AjaxResult mergeFile(@RequestBody TFileInfoVO chunk) {//TFileInfoVO
        // 查询片数据
        try {
            List<String> objectNameList = minioService.listObjectNames(chunk.getUniqueIdentifier());
            if(objectNameList!=null&&objectNameList.size()==chunk.getTotalChunks()){
//                //合并
                long timeStart = System.currentTimeMillis();
                logger.info("合并文件开始.............");
                String bucket = !StringUtils.isEmpty(chunk.getBucket())?chunk.getBucket(): DateUtil.format(new Date(),"yyyy-MM-dd");
                String objectName = StringUtils.isEmpty(chunk.getFolder())?chunk.getRelativePath():chunk.getFolder()+"/"+chunk.getRelativePath();
                MinioFile minioFile = minioService.
                        composeObject(chunk.getUniqueIdentifier(), bucket, objectName);
                logger.info("合并文件删除分片文件.............");
                fileChunkInfoService.deleteFileChunkInfoByIdentifier(chunk.getUniqueIdentifier());
                minioService.removeBucket(chunk.getUniqueIdentifier(),true);
//                fileInfoService.saveUploadFile(chunk,minioFile);
                //合并操作在具体的业务提交后再操作合并，上传到具体业务的bucket中
//                logger.info("合并文件redis缓存.............");
                //放到redis中
//                redisCache.setCacheObject(minio_key+chunk.getUniqueIdentifier(),true,1000, TimeUnit.SECONDS);
                long timeEnd = System.currentTimeMillis();
                logger.info("合并文件成功 ，消费时间:  {}s.............",(timeEnd-timeStart)/1000);
                return AjaxResult.success("上传文件成功",minioFile);
            }else {
                //上传的分片数量不对，不能合并，删除让用户重新上传
                fileChunkInfoService.deleteFileChunkInfoByIdentifier(chunk.getUniqueIdentifier());
                minioService.removeBucket(chunk.getUniqueIdentifier(),true);
                return AjaxResult.error("上传文件失败,文件分片和已上传的分片数不一致");
            }
        } catch (Exception e) {
            logger.error("合并文件异常.............",e);
            return AjaxResult.error("上传文件失败");
        }
    }
}
